home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 May: Tool Chest / Developer CD Series Tool Chest (Apple Computer)(May 1999).iso / Tool Chest / Development Kits / MPW etc / MPW-GM / MPW / Examples / AExamples / Sample.a < prev    next >
Encoding:
Text File  |  1998-12-03  |  39.3 KB  |  1,006 lines  |  [TEXT/MPS ]

  1. *
  2. *    Apple Macintosh Developer Technical Support
  3. *
  4. *    MultiFinder-Aware Simple Sample Application
  5. *
  6. *    Sample
  7. *
  8. *    Sample.a    -    Assembler Source
  9. *
  10. *    Copyright © Apple Computer, Inc. 1989-1990, 1993
  11. *    All rights reserved.
  12. *
  13. *    Versions:    
  14. *        1.00            08/88
  15. *        1.01            11/88
  16. *        1.02            04/89    MPW 3.1
  17. *        1.03            02/90    MPW 3.2
  18. *        1.04            11/93    MPW 3.3.1 (ETO 13)
  19. *        1.05            1/96    MPW 3.4 (ETO 20)
  20. *
  21. *    Components:
  22. *        Sample.a        Feb. 1, 1990
  23. *        Sample.inc1.a    Feb. 1, 1990
  24. *        SampleMisc.a    Feb. 1, 1990
  25. *        Sample.r        Feb. 1, 1990
  26. *        Sample.h        Feb. 1, 1990
  27. *        Sample.make        Feb. 1, 1990
  28. *
  29. *    Sample is an example application that demonstrates how to
  30. *    initialize the commonly used toolbox managers, operate 
  31. *    successfully under MultiFinder, handle desk accessories, 
  32. *    and create, grow, and zoom windows.
  33. *
  34. *    It does not by any means demonstrate all the techniques 
  35. *    you need for a large application. In particular, Sample 
  36. *    does not cover exception handling, multiple windows/documents, 
  37. *    sophisticated memory management, printing, or undo. All of 
  38. *    these are vital parts of a normal full-sized application.
  39. *
  40. *    This application is an example of the form of a Macintosh 
  41. *    application; it is NOT a template. It is NOT intended to be 
  42. *    used as a foundation for the next world-class, best-selling, 
  43. *    600K application. A stick figure drawing of the human body may 
  44. *    be a good example of the form for a painting, but that does not 
  45. *    mean it should be used as the basis for the next Mona Lisa.
  46. *
  47. *    We recommend that you review this program or TESample before 
  48. *    beginning a new application.
  49.  
  50. * This example program is to be considered an introduction to coding in the
  51. * MPW Assembly language.  This sample program demonstrates the use of RECORD,
  52. * PROC, WITH, MACROs, IMPORT, and other coding practices used by MPW.  Although
  53. * this code will not be compatible with other assemblers, there is enough code
  54. * contained within the procedures that demonstrate 68000 programming on the Mac.
  55.  
  56. * The main purpose of this example is to have an easy to understand sample
  57. * assembly program that follows very closely the same sample program available
  58. * in Pascal and C.  Programmers not familiar with assembly code should refer to
  59. * these high level versions and follow the procedures while examining the assembly
  60. * code.  This is a great way to learn how to read assembly listings, and that is
  61. * the first step in using a debugger.
  62.  
  63. * Stack frame strategy:
  64. * -----------------------------------------------
  65. * Here is an example of a typical stack frame.  An example of the stack frame
  66. * RECORD is shown.  Using this strategy for procedures makes life much easier
  67. * while writing assembly code.  The procedure outlined in Pascal here is
  68. * followed by the same outline in assembly.
  69.  
  70. * PROCEDURE MyProcedure (Param1: type, Param2: type, ParamN: type) Result1: type;
  71.  
  72. * VAR    Local1: type;
  73. *    Local2: type;
  74. *    LocalN: type;
  75.  
  76.  
  77. * MyProcedure    PROC    EXPORT            ; any source file can use this routine
  78.  
  79. * define registors that need to be saved as EQUATES (typically A3-A7 and D4-D7)
  80.  
  81. * StackFrame    RECORD    {A6Link},DECR        ; build a stack frame record
  82. * Result1    DS.{size}            ; function's result returned to caller
  83. * ParamBegin    EQU    *            ; start parameters after this point
  84. * Param1    DS.{size}            ; the first parameter on the stack
  85. * Param2    DS.{size}            ; rest of the parameters passed by caller
  86. * ParamN    DS.{size}            ; the last parameter passed by caller
  87. * ParamSize    EQU    ParamBegin-*        ; size of all the passed parameters
  88. * RetAddr     DS.L    1            ; place holder for return address
  89. * A6Link    DS.L    1            ; place holder for A6 link
  90. * Local1    DS.{size}            ; a local variable for this procedure only
  91. * Local2    DS.{size}            ; other local variables for this procedure
  92. * LocalN    DS.{size}            ; the last local variable
  93. * LocalSize    EQU     *            ; size of all the local variables
  94. *         ENDR
  95.  
  96. *         WITH    StackFrame        ; cover our local stack frame
  97. *         LINK    A6,#LocalSize        ; allocate our local stack frame
  98.  
  99. *        save registors trashed by this routine
  100.  
  101. *         # # INSERT YOUR CODE HERE # #
  102.  
  103. * Exit        restore registors trashed by this routine
  104. *         UNLK    A6            ; destroy the link
  105. *         MOVEA.L    (SP)+,A0        ; pull off the return address
  106. *         ADDA.L    #ParamSize,SP        ; strip all of the caller's parameters
  107. *         JMP    (A0)            ; return to the caller
  108. *         DbgInfo    MyProcedure        ; this name will appear in the debugger
  109. *         ENDP
  110.  
  111. * The Macro DbgInfo is optional.  I prefer to use it, since it aids in
  112. * debugging.  There are more macros in the "AStructMacs" folder of MPW.  Put on
  113. * a pot of coffee and take a look at them and the Sample program that uses these
  114. * macros.  There is one macro in particular that builds the entire stack frame
  115. * structure as outlined above, including the debug info.
  116.  
  117. * Segmentation strategy:
  118. * -----------------------------------------------
  119. * This program consists of three segments. Main contains most of the code.
  120. * Initialize contains code that is only used once, during startup, and can be
  121. * unloaded after the program starts. %A5Init is automatically created by the
  122. * Linker to initialize globals and constants, and is unloaded right away.
  123.  
  124. * SetPort strategy:
  125. * -----------------------------------------------
  126. * Tool box routines do not change the current port. In spite of this, in this
  127. * program we use a strategy of calling SetPort whenever we want to draw or
  128. * make calls which depend on the current port. This makes us less vulnerable
  129. * to bugs in other software which might alter the current port (such as the
  130. * bug (feature?) in many desk accessories which change the port on OpenDeskAcc).
  131. * Hopefully, this also makes the routines from this program more self-contained,
  132. * since they don't depend on the current port setting.
  133.  
  134. * ================================================
  135. * -------------- INCLUDES SECTION ----------------
  136. * ================================================
  137.     
  138.     PRINT    PUSH,OFF            ; don't print any of this stuff
  139.  
  140. OLDROUTINENAMES SET 1
  141.  
  142.     INCLUDE 'LowMemEqu.a'
  143.  
  144.     INCLUDE 'DiskInit.a'
  145.     INCLUDE 'Devices.a'
  146.     INCLUDE 'SegLoad.a'
  147.     INCLUDE 'Menus.a'
  148.     INCLUDE 'Memory.a'
  149.     INCLUDE 'LowMemEqu.a'
  150.     INCLUDE 'Dialogs.a'
  151.     INCLUDE 'Fonts.a'
  152.     INCLUDE 'Windows.a'
  153.     INCLUDE 'Traps.a'
  154.     INCLUDE    'Quickdraw.a'
  155.     INCLUDE 'Packages.a'
  156.     INCLUDE 'ToolUtils.a'
  157.  
  158.     INCLUDE    'Sample.inc1.a'            ; all our macros and data templates
  159.     
  160.  
  161.     PRINT    POP                ; restore the PRINT options
  162.     
  163.  
  164. * ================================================
  165. * ---------  DATA STORAGE ALLOCATION  ------------
  166. * ================================================
  167. * Global data storage.  All global memory is allocated here.  The
  168. * Linker will load all global data offset from A5, and the Asm knows this.
  169. * Therefore, no reference to (A5) is required in the code. Hooray!
  170. * Here we declare two data structures using our templates defined previously.
  171. * They must be EXPORTed here for other files that need to IMPORT them.
  172.  
  173.         EXPORT    (QD,G):DATA
  174.  
  175. QD        DS    QDGlobals        ; QuickDraw's globals
  176. G        DS    AppGlobals        ; application's globals
  177.  
  178.  
  179. * ================================================
  180. * PROCEDURE Initialize;
  181. * ================================================
  182. * Set up the whole world, including global variables, Toolbox managers, and menus.
  183. * Check to see if a given trap is implemented. The recommended approach to see if
  184. * a trap is implemented is to see if the address of the trap routine is the same
  185. * as the address of the Unimplemented trap.  We also create our one application
  186. * window at this time.  Since window storage is non-relocateable, how and when to
  187. * allocate space for windows is very important so that heap fragmentation does not
  188. * occur.  Because Sample has only one window and it is only disposed when the
  189. * application quits, we will allocate its space here, before anything that might
  190. * be a locked relocatable object gets into the heap. This way, we can force its
  191. * storage to be in the lowest memory available in the heap. Window storage can
  192. * differ widely amongst applications depending on how many windows are created
  193. * and disposed.  If a failure occurs here, we will consider that the application
  194. * is in such bad shape that we should just exit. Your error handling may differ,
  195. * but the checks should still be made.
  196.  
  197. * If an error is detected, instead of merely doing an ExitToShell, which leaves
  198. * the user without much to go on, we call AlertUser, which puts up a simple alert
  199. * that just says an error occurred and then calls ExitToShell.  In the interests
  200. * of keeping things simple, the alert does not state the specific cause of the error,
  201. * but a more informative alert would be appropriate for more sophisticated applications.
  202. * Since there is no other cleanup needed at this point if an error is detected, this
  203. * form of error- handling is acceptable. If more sophisticated error recovery is needed,
  204. * a signal mechanism, such as is provided by Signals, can be used.
  205.  
  206. * Something worth noting here.  Since the AlertUser routine is in a different segment,
  207. * we have to use a Jump instruction to get there.  In other words, we must go through the
  208. * jump table.  This causes extra test and branch instructions to get over the JMP AlertUser.
  209.  
  210.         SEG 'Initialize'                ; case sensitive
  211. Initialize    PROC                        ; Initialize everything
  212.  
  213. CountReg    EQU    D4                        ; temporary registor to count loops
  214.  
  215. StackFrame    RECORD    {A6Link},DECR        ; build a stack frame record
  216. ParamBegin    EQU    *                        ; start parameters after this point
  217. ParamSize    EQU    ParamBegin-*            ; size of all the passed parameters
  218. RetAddr     DS.L    1                    ; place holder for return address
  219. A6Link        DS.L    1                    ; place holder for A6 link
  220. CurMBar        DS.L    1                    ; local handle to our menubar
  221. TheEvent     DS    EventRecord             ; local copy of the event record
  222. LocalSize    EQU     *                    ; size of all the local variables
  223.         ENDR
  224.         
  225.         IMPORT    GoGetRect,AlertUser,SysEnvirons,    \
  226.             TrapAvailable                ; linked in with Runtime.o
  227.  
  228.         WITH    StackFrame                ; cover our local stack frame
  229.         LINK    A6,#LocalSize            ; allocate our local stack frame
  230.         
  231.         MOVEM.L    CountReg,-(SP)             ; save the current registor values
  232.         MOVE.W    #False,G.InBackground    ; we start out in the foreground
  233.         MOVE.W    #True100,G.Stopped        ; we'll start with the red light on
  234.  
  235. * ------------- INITIALIZE MANAGERS -------------
  236.  
  237. @1        PEA     QD.thePort         ; initialize all of the Managers
  238.         _InitGraf                ; please don't flush my events
  239.         _InitFonts
  240.         _InitWindows
  241.         _InitMenus
  242.         _TEInit
  243.         CLR.L    -(SP)    
  244.         _InitDialogs
  245.         _InitCursor
  246.         
  247. * Call MPPOpen and ATPLoad at this point to initialize AppleTalk, if you are using it.
  248. * NOTE -- It is no longer necessary, and actually unhealthy, to check PortBUse and
  249. * SPConfig before opening AppleTalk. The drivers are capable of checking for port
  250. * availability themselves.  This next bit of code is necessary to allow the default
  251. * button of our alert be outlined.
  252.      
  253. * ------------- WASTE THREE EVENTS -------------
  254.  
  255.         MOVE.W    #2,CountReg            ; set register value to loop 3 times
  256. Loop        CLR.W    -(SP)            ; space for result
  257.         MOVE.W    #EveryEvent,-(SP)    ; the events we want
  258.         PEA    TheEvent(A6)            ; pass a pointer to our event
  259.         _EventAvail
  260.         MOVE.W    (SP)+,D0            ; result code
  261.         DBF    CountReg,Loop            ; decrement count, if count < 0 then continue
  262.  
  263. * ------------- GET THE ENVIRONMENT -------------
  264.  
  265.         CLR.W    -(SP)                    ; create space for result
  266.         MOVE.W    #EnvironsVersion,-(SP)    ; version of SysEnvirons we want
  267.         PEA    G.Mac                        ; the global environment record
  268.         JSR    SysEnvirons                    ; we can ignore any errors here,
  269.         MOVE.W    (SP)+,D0                ; SysEnvirons will fill in regardless
  270.         MOVE.W    G.Mac.MachineType,D0     ; negitive value means old ROMs
  271.         BPL.S    @2                        ; 128k ROMs or better, continue on
  272.         JMP    AlertUser                    ; we don't want to run on 64k ROMs
  273.  
  274. * ------------- TEST FOR WAITNEXTEVENT -------------
  275. * 1.02 - Move TrapAvailable call to after SysEnvirons so that
  276. * we can tell in TrapAvailable if a tool trap value is out of range.
  277.  
  278. @2        CLR.W    -(SP)                    ; space for result of trap test
  279.         MOVE.W    #WaitNextEvent,-(SP)    ; pass the trap number of WaitNextEvent trap
  280.         JSR    TrapAvailable                ; test for this trap
  281.         MOVE.W    (SP)+,G.HasWNEvent        ; put the result in our global flag
  282.             
  283. * ------------- CHECK FOR ENOUGH MEMORY -------------
  284. * It is better to first check the size of the application heap against a value
  285. * that you have determined is the smallest heap the application can reasonably
  286. * work in. This number should be derived by examining the size of the heap that
  287. * is actually provided by MultiFinder when the minimum size requested is used.
  288. * The derivation of the minimum size requested from MultiFinder is described
  289. * in ASample.r. The check should be made because the preferred size can end up
  290. * being set smaller than the minimum size by the user. This extra check acts to
  291. * insure that your application is starting from a solid memory foundation.
  292.  
  293. *    IF applLimit - applZone < MinHeap THEN AlertUser
  294.  
  295. * Next, make sure that enough memory is free for your application to run. It
  296. * is possible for a situation to arise where the heap may have been of required
  297. * size, but a large scrap was loaded which left too little memory. To check for
  298. * this, call PurgeSpace and compare the result with a value that you have determined
  299. * is the minimum amount of free memory your application needs at initialization.
  300. * This number can be derived several different ways. One way that is fairly
  301. * straightforward is to run the application in the minimum size configuration
  302. * as described previously. Call PurgeSpace at initialization and examine the value
  303. * returned. However, you should make sure that this result is not being modified
  304. * by the scrap's presence. You can do that by calling ZeroScrap before calling
  305. * PurgeSpace. Make sure to remove that call before shipping, though.
  306.  
  307. * The extra benefit to waiting until after the Toolbox Managers have been initialized
  308. * before checking memory is that we can now give the user an alert to tell him what
  309. * happened. Although it is possible that the memory situation could be worsened by
  310. * displaying an alert, MultiFinder would gracefully exit the application with
  311. * an informative alert if memory became critical. Here we are acting more
  312. * in a preventative manner to avoid future disaster from low-memory problems.
  313.  
  314.         MOVE.L    applLimit,D1        ; get pointer to ApplLimit
  315.         MOVE.L    applZone,D0            ; get pointer to ApplicZone
  316.         SUB.L    D0,D1                ; subtract the ApplicZone from ApplLimit
  317.         CMPI.L    #MinHeap,D1            ; do we have enough memory?
  318.         BPL.S    @3                    ; yes we do, continue on
  319.         JMP    AlertUser                ; no, report the error
  320.         
  321. @3        _PurgeSpace                    ; results will be in A0 and D0
  322.         CMPI.L    #MinSpace,D0        ; do we have enough purgeable space?
  323.         BPL.S    @4
  324.         JMP    AlertUser                ; no, report the error
  325.  
  326. * ------------- SET UP THE TRAFFIC LIGHT WINDOW -------------
  327. * We will allocate our own window storage instead of letting the Window Manager
  328. * for two reasons. One, GetNewWindow locks the 'WIND' resource handle before calling
  329. * NewWindow and this can lead to heap fragmentation.  Two, it takes just as much time
  330. * for NewWindow to get the memory as it does for us to get it.
  331.  
  332. @4        MOVE.L    #WindowRecord.sizeof,D0
  333.         _NewPtr ,Clear            ; create a pointer in A0 and clear memory
  334.         CMPA.L    #0,A0            ; check for NIL pointer (result in D0)
  335.         BNE.S    @5                ; must have been a valid pointer
  336.         JMP    AlertUser            ; couldn't get memory, report error
  337.         
  338. @5        CLR.L    -(SP)            ; create space for result
  339.         MOVE.W    #rWindow,-(SP)    ; out window resource definition
  340.         MOVE.L    A0,-(SP)        ; our window record storage
  341.         MOVE.L    #-1,-(SP)        ; make it on top
  342.         _GetNewWindow            ; create the window
  343.         MOVE.L    (SP)+,D0        ; we're not saving our window pointer
  344.         
  345. * ------------- SET UP THE MENUS -------------
  346.     
  347.         CLR.L    -(SP)                ; space for MenuBar handle
  348.         MOVE.W    #rMenuBar,-(SP)        ; our MenuBar resource
  349.         _GetNewMBar                    ; the modern way, get a MenuBar
  350.         MOVE.L    (SP),CurMBar(A6)
  351.         _SetMenuBar
  352.         MOVEA.L    CurMBar(A6),A0        ; we're done with that handle
  353.         _DisposeHandle                ; there is a result in D0
  354.         CLR.L    -(SP)
  355.         MOVE.W    #AppleMenu,-(SP)
  356.         _GetMenuHandle                ; put Apple menu handle on stack
  357.         MOVE.L    #'DRVR',-(SP)        ; get all the DAs
  358.         _AppendResMenu
  359.         _DrawMenuBar
  360.  
  361. * ------------- SET UP RECTS FOR THE LIGHTS  -------------
  362.  
  363.         CLR.W    -(SP)                ; space for result of GoGetRect
  364.         MOVE.W    #rStopRect,-(SP)    ; pass the stop light's rect
  365.         PEA    G.StopRect                ; pass the stop light's rect pointer
  366.         BSR    GoGetRect                ; go get the stop light rect
  367.         MOVE.W    (SP)+,D0            ; get the result of GoGetRect
  368.         CMPI.W    #True100,D0            ; did we get the RECT resource?
  369.         BEQ.S    @6                    ; yes, then continue
  370.         JMP    AlertUser                ; otherwise, we're having some trouble
  371.         
  372. @6        CLR.W    -(SP)                ; space for result of GoGetRect
  373.         MOVE.W    #rGoRect,-(SP)        ; pass the go light's rect
  374.         PEA    G.GoRect                ; pass the go light's rect pointer
  375.         BSR    GoGetRect                ; go get the go light rect
  376.         MOVE.W    (SP)+,D0            ; get the result of GoGetRect
  377.         CMPI.W    #True100,D0            ; did we get the RECT resource?
  378.         BEQ.S    Exit                ; yes, then continue
  379.         JMP    AlertUser                ; otherwise, we're having some trouble
  380.                 
  381. Exit        MOVEM.L    (SP)+,CountReg    ; restore the registors
  382.         UNLK    A6                    ; destroy the link
  383.         MOVEA.L    (SP)+,A0            ; pull off the return address
  384.         ADDA.L    #ParamSize,SP        ; strip all of the caller's parameters
  385.         JMP    (A0)                    ; return to the caller
  386.  
  387.         DbgInfo    Initialz            ; this name will appear in the debugger
  388.         ENDP
  389.  
  390. * ================================================
  391. * PROCEDURE DoContentClick(window: WindowPtr; event: EventRecord);
  392. * ================================================
  393. * This is called when a mouse-down event occurs in the content of a window.
  394. * Other applications might want to call FindControl, TEClick, etc., to
  395. * further process the click.
  396.  
  397.         SEG    'Main'                        ; case sensitive
  398. DoContentClick    PROC
  399.  
  400. StackFrame    RECORD    {A6Link},DECR        ; build a stack frame record
  401. ParamBegin    EQU    *                        ; start parameters after this point
  402. WindowPtr    DS.L    1                    ; passed parameter of the window pointer
  403. EventPtr    DS.L    1                    ; pointer to the event record
  404. ParamSize    EQU    ParamBegin-*            ; size of all the passed parameters
  405. RetAddr     DS.L    1                    ; place holder for return address
  406. A6Link        DS.L    1                    ; place holder for A6 link
  407. LocalSize    EQU     *                    ; size of all the local variables
  408.         ENDR
  409.         
  410.         IMPORT    SetLight
  411.  
  412.         WITH    StackFrame                ; cover our local stack frame
  413.         LINK    A6,#LocalSize            ; allocate our local stack frame
  414.  
  415.          MOVE.L    WindowPtr(A6),-(SP)        ; pass the window pointer
  416.         MOVE.W    G.Stopped,D0            ; get current state of the light
  417.         EORI.W    #True100,D0                ; exclusive OR the current state
  418.         MOVE.W    D0,-(SP)                ; pass new state to switch light
  419.         BSR    SetLight                    ; set the traffic light
  420.  
  421. Exit        UNLK    A6                    ; destroy the link
  422.         MOVEA.L    (SP)+,A0                ; pull off the return address
  423.         ADDA.L    #ParamSize,SP            ; strip all of the caller's parameters
  424.         JMP    (A0)                        ; return to the caller
  425.  
  426.         DbgInfo    DoContnt                ; this name will appear in the debugger
  427.         ENDP
  428.  
  429. * ================================================
  430. * PROCEDURE DoUpdate(window: WindowPtr);
  431. * ================================================
  432. * This is called when an update event is received for a window.
  433. * It calls DrawWindow to draw the contents of an application window.
  434. * As an efficiency measure that does not have to be followed, it
  435. * calls the drawing routine only if the visRgn is non-empty. This
  436. * will handle situations where calculations for drawing or drawing
  437. * itself is very time-consuming.
  438.  
  439.         SEG    'Main'                        ; case sensitive
  440. DoUpdate    PROC
  441.  
  442. StackFrame    RECORD    {A6Link},DECR        ; build a stack frame record
  443. ParamBegin    EQU    *                        ; start parameters after this point
  444. WindowPtr    DS.L    1                    ; passed parameter of the window pointer
  445. ParamSize    EQU    ParamBegin-*            ; size of all the passed parameters
  446. RetAddr     DS.L    1                    ; place holder for return address
  447. A6Link        DS.L    1                    ; place holder for A6 link
  448. LocalSize    EQU     *                    ; size of all the local variables
  449.         ENDR
  450.         
  451.         IMPORT    IsAppWindow,DrawWindow
  452.  
  453.         WITH    StackFrame                    ; cover our local stack frame
  454.         LINK    A6,#LocalSize                ; allocate our local stack frame
  455.  
  456.         CLR.W    -(SP)                        ; space for result of IsAppWindow
  457.         MOVE.L    WindowPtr(A6),-(SP)            ; pass the window pointer
  458.         BSR    IsAppWindow                        ; test if this window was ours
  459.         MOVE.W    (SP)+,D0        
  460.         CMPI.W    #True100,D0                    ; it must be our window
  461.         BNE.S    Exit                        ; it wasn't our window
  462.         
  463.         MOVE.L    WindowPtr(A6),-(SP)            ; update only the visible region
  464.         _BeginUpDate                        ; region of the window
  465.         CLR.W    -(SP)                        ; space for result
  466.         MOVEA.L    WindowPtr(A6),A0            ; the window pointer
  467.         MOVE.L    GrafPort.visRgn(A0),-(SP)    ; the window's visRgn handle
  468.         _EmptyRgn
  469.         MOVE.W    (SP)+,D0                    ; result of EmptyRgn
  470.         CMPI.W    #True100,D0                    ; was the visRgn empty?
  471.         BEQ.S    @1                            ; yes, then no update is needed
  472.         
  473.         MOVE.L    WindowPtr(A6),-(SP)
  474.         BSR    DrawWindow                        ; draw the traffic lights
  475.         
  476. @1        MOVE.L    WindowPtr(A6),-(SP)            ; get pointer to window
  477.         _EndUpdate
  478.  
  479. Exit        UNLK    A6                        ; destroy the link
  480.         MOVEA.L    (SP)+,A0                    ; pull off the return address
  481.         ADDA.L    #ParamSize,SP                ; strip all of the caller's parameters
  482.         JMP    (A0)                            ; return to the caller
  483.  
  484.         DbgInfo    DoUpdate                    ; this name will appear in the debugger
  485.         ENDP
  486.  
  487. * ================================================
  488. * PROCEDURE DoActivate(window: WindowPtr; becomingActive: BOOLEAN);
  489. * ================================================
  490. * In this sample there is no other processing necessary other than what
  491. * the Window Manager has already done for us.  This would be the place to
  492. * perform an activate on TextEdit records, controls, lists, update GrowIcon, etc.
  493.  
  494.         SEG    'Main'                        ; case sensitive
  495. DoActivate    PROC
  496.  
  497. StackFrame    RECORD    {A6Link},DECR        ; build a stack frame record
  498. ParamBegin    EQU    *                        ; start parameters after this point
  499. WindowPtr    DS.L    1                    ; passed parameter of the window pointer
  500. Active        DS.W    1                    ; modifiers from the event record
  501. ParamSize    EQU    ParamBegin-*            ; size of all the passed parameters
  502. RetAddr     DS.L    1                    ; place holder for return address
  503. A6Link        DS.L    1                    ; place holder for A6 link
  504. LocalSize    EQU     *                    ; size of all the local variables
  505.         ENDR
  506.         
  507.         IMPORT    IsAppWindow
  508.  
  509.         WITH    StackFrame                ; cover our local stack frame
  510.         LINK    A6,#LocalSize            ; allocate our local stack frame
  511.  
  512.         CLR.W    -(SP)                    ; space for result of IsAppWindow
  513.         MOVE.L    WindowPtr(A6),-(SP)        ; pass the window pointer
  514.         BSR    IsAppWindow                    ; test if this window was ours
  515.         MOVE.W    (SP)+,D0                ; get the result
  516.         CMPI.W    #True100,D0                ; it must be our window
  517.         BNE.S    Exit                    ; it wasn't our window
  518.  
  519.         CMPI.W    #True100,Active(A6)        ; was it an Activate?
  520.         BNE.S    DeActivate                ; no, perform a Deactivate
  521.         
  522. * do the activate event processing here, then "BRA.S   Exit"
  523.         
  524. DeActivate                                ; do the deactivate event
  525.  
  526. * do the deactivate event processing here, then fall through to Exit
  527.         
  528.  
  529. Exit        UNLK    A6                    ; destroy the link
  530.         MOVEA.L    (SP)+,A0                ; pull off the return address
  531.         ADDA.L    #ParamSize,SP            ; strip all of the caller's parameters
  532.         JMP    (A0)                        ; return to the caller
  533.  
  534.         DbgInfo    Activate                ; this name will appear in the debugger
  535.         ENDP
  536.                     
  537. * ================================================
  538. * PROCEDURE DoMenuCommand(menuResult: LONGINT);
  539. * ================================================
  540. * This is called when an item is chosen from the menu bar (after calling
  541. * MenuSelect or MenuKey). It performs the right operation for each command.
  542. * It is good to have both the result of MenuSelect and MenuKey go to
  543. * one routine like this to keep everything organized.
  544.  
  545.         SEG    'Main'                        ; case sensitive
  546. DoMenuCommand    PROC
  547.  
  548. StackFrame    RECORD    {A6Link},DECR        ; build a stack frame record
  549. ParamBegin    EQU    *                        ; start parameters after this point
  550. MenuItem    DS.W    1                    ; result from _MenuKey or _MenuSelect
  551. MenuID        DS.W    1                    ; caller passed a long word, ID + Item
  552. ParamSize    EQU    ParamBegin-*            ; size of all the passed parameters
  553. RetAddr     DS.L    1                    ; place holder for return address
  554. A6Link        DS.L    1                    ; place holder for A6 link
  555. Deskname    DS.B    256                    ; local storage for Desk Accs name
  556. TempPort    DS.L    1                    ; local storage for the current port
  557. LocalSize    EQU     *                    ; size of all the local variables
  558.         ENDR
  559.         
  560.         IMPORT    SetLight,DoCloseWindow,Terminate
  561.  
  562.         WITH    StackFrame                ; cover our local stack frame
  563.         LINK    A6,#LocalSize            ; allocate our local stack frame
  564.  
  565.         MOVE.W    MenuID(A6),D0            ; a nifty Pascal case-like macro
  566.         CASE#.W    (D0,IF),            \
  567.             (AppleMenu,    DoAppleMenu),    \
  568.             (FileMenu,    DoFileMenu),    \
  569.             (EditMenu,    DoEditMenu),    \
  570.             (LightMenu,    DoLightMenu)
  571.                                         
  572.                                         ; add additional Menus would go here
  573.         BRA.W    Exit                    ; otherwise we will exit this procedure
  574.  
  575. * ------------- THE APPLE MENU ROUTINES -------------
  576. DoAppleMenu
  577.         CMPI.W    #AboutItem,MenuItem(A6)        ; was it the about item?
  578.         BNE.S    @1                            ; no, must be a Desk Acc
  579.  
  580.         CLR.W    -(SP)                        ; show the About dialog
  581.         MOVE.W    #rAboutAlert,-(SP)            ; resource for alert dialog
  582.         CLR.L    -(SP)                        ; no filter procedure used here
  583.         _Alert                                ; read the resource and display it
  584.         MOVE.W    (SP)+,D0                    ; I don't care which item is was
  585.         BRA.W    Exit                        ; all done with with Apple menu
  586.  
  587. @1        PEA    TempPort(A6)                    ; open a desk accessory
  588.         _GetPort                            ; save the current port
  589.         CLR.L    -(SP)                        ; space for result of GetMHandle
  590.         MOVE.W    #AppleMenu,-(SP)
  591.         _GetMenuHandle                        ; put Apple menu on stack
  592.         MOVE.W    MenuItem(A6),-(SP)            ; and here's the MenuItem
  593.         PEA    DeskName(A6)                    ; now tell me the DA's name
  594.         _GetMenuItemText
  595.         CLR.W    -(SP)                        ; space for OpenDeskAcc result
  596.         PEA    DeskName(A6)
  597.         _OpenDeskAcc                        ; open that puppy
  598.         MOVE.W    (SP)+,D0                    ; result
  599.         MOVE.L    TempPort(A6),-(SP)            ; restore the port
  600.         _SetPort
  601.         BRA.S    Exit
  602.         
  603. * ------------- THE FILE MENU ROUTINES -------------
  604. DoFileMenu    
  605.         MOVE.W    MenuItem(A6),D0             ; test the MenuItem
  606.         Case#.W    (D0,IF),            \
  607.             (CloseItem,    FileClose),    \
  608.             (QuitItem,    FileQuit)
  609.         BRA.S    Exit                        ; add additional menus here
  610. FileClose
  611.         CLR.L    -(SP)                        ; bug fix, didn't clear space for result -JDR 2/27/89
  612.         _FrontWindow
  613.         BSR    DoCloseWindow                    ; close the window 
  614.         BRA.S    Exit
  615.  
  616. FileQuit    BSR    Terminate                    ; let's get out of here
  617.         BRA.S    Exit                        ; Terminate may return if user cancels
  618.         
  619.  
  620. * ------------- THE EDIT MENU ROUTINES -------------
  621. DoEditMenu    
  622.         CLR.W    -(SP)                    ; system will handle editing of desk accs.
  623.         MOVE.W    MenuItem(A6),-(SP)        ; get the MenuItem
  624.         SUBQ.W    #1,(SP)                    ; SystemEdit is off by one
  625.         _SystemEdit
  626.         MOVE.B    (SP)+,D0                ; drop result from SystemEdit
  627.         BRA.S    Exit                    ; we don't have anything to edit
  628.  
  629. * ------------- THE LIGHT MENU ROUTINES -------------
  630. DoLightMenu    
  631.         MOVE.W    MenuItem(A6),D0         ; test the MenuItem
  632.         Case#.W    (D0,IF),            \
  633.             (StopItem,    StopSelect),    \
  634.             (GoItem,    GoSelect)
  635.         BRA.S    Exit                    ; add additional menus here
  636.  
  637. StopSelect    CLR.L    -(SP)                ; bug fix, didn't clear space for result -JDR 2/27/89
  638.         _FrontWindow                    ; pass our window, we only have one
  639.         MOVE.W    #True100,-(SP)            ; pass true to set stop light on
  640.         BSR    SetLight                    ; switch the traffic light
  641.         BRA.S    Exit        
  642.  
  643. GoSelect    CLR.L    -(SP)                ; bug fix, didn't clear space for result -JDR 2/27/89
  644.         _FrontWindow                    ; pass our window, we only have one
  645.         MOVE.W    #FALSE,-(SP)            ; pass false to set stop light off
  646.         BSR    SetLight                    ; switch the traffic light
  647.         
  648. Exit        CLR.W    -(SP)    
  649.         _HiLiteMenu                        ; unhilite all Menus
  650.         UNLK    A6                        ; destroy the link
  651.         MOVEA.L    (SP)+,A0                ; pull off the return address
  652.         ADDA.L    #ParamSize,SP            ; strip all of the caller's parameters
  653.         JMP    (A0)                        ; return to the caller
  654.  
  655.         DbgInfo    DoMenuCm                ; this name will appear in the debugger
  656.         ENDP
  657.         
  658. * ================================================
  659. * PROCEDURE DoMouseDown(Event: EventRecord);
  660. * ================================================
  661. * Handle all of the MouseDown events.
  662.  
  663.         SEG    'Main'                        ; case sensitive
  664. DoMouseDown    PROC
  665.  
  666. StackFrame    RECORD    {A6Link},DECR        ; build a stack frame record
  667. ParamBegin    EQU    *                        ; start parameters after this point
  668. EventPtr     DS.L    1                     ; pointer to current event
  669. ParamSize    EQU    ParamBegin-*            ; size of all the passed parameters
  670. RetAddr     DS.L    1                    ; place holder for return address
  671. A6Link        DS.L    1                    ; place holder for A6 link
  672. WindowPtr    DS.L    1                    ; local Window pointer variable
  673. Mouse        DS.L    1                    ; local variable where the click was
  674. NewGrowRect    DS    Rect                    ; local rect variable for SizeWindow
  675. LocalSize    EQU     *                    ; size of all the local variables
  676.             ENDR
  677.             
  678.         IMPORT    AdjustMenus,DoContentClick
  679.  
  680.         WITH    StackFrame                ; cover our local stack frame
  681.         LINK    A6,#LocalSize            ; allocate our local stack frame
  682.  
  683.         MOVEA.L    EventPtr(A6),A0                    ; event record only needed by SystemClick
  684.         MOVE.L    EventRecord.where(A0),Mouse(A6)    ; store mouse location
  685.  
  686.         CLR.W    -(SP)                            ; space for FindWindow result
  687.         MOVE.L    Mouse(A6),-(SP)                    ; the mouse point
  688.         PEA        WindowPtr(A6)                    ; a local variable
  689.         _FindWindow                                ; put the result in a register
  690.         MOVE.W    (SP)+,D0                        ; a nifty Pascal case-like macro
  691.         Case#.W    (D0,IF),            \
  692.             (InMenuBar,    MenuEvent),    \
  693.             (InSysWindow,    SystemEvent),    \
  694.             (InContent,    Content),    \
  695.             (InDrag,    Drag)
  696.                                         ; add additional routines here
  697.         BRA.S    Exit                    ; otherwise we will exit this procedure
  698.  
  699. * ------------- THE DESK ACCS EVENT -------------
  700. MenuEvent    
  701.         BSR.W    AdjustMenus
  702.         CLR.L    -(SP)                    ; space for MenuSelect
  703.         MOVE.L    Mouse(A6),-(SP)            ; Mouse coordinates
  704.         _MenuSelect                        ; pass MenuSelect's result
  705.         BSR    DoMenuCommand                ; go do the menu and return
  706.         BRA.S    Exit
  707.  
  708. * ------------- THE DESK ACCS EVENT -------------
  709. SystemEvent    
  710.         MOVE.L    EventPtr(A6),-(SP)        ; get EventRecord and WindowPtr
  711.         MOVE.L    WindowPtr(A6),-(SP)        ; pass the window pointer and...
  712.         _SystemClick                    ; let the system handle it
  713.         BRA.S    Exit
  714.  
  715. * ------------- THE CONTENT EVENT -------------
  716. Content            
  717.         CLR.L    -(SP)                    ; was our window in front?
  718.         _FrontWindow                    ; get front window's pointer
  719.         MOVE.L    (SP)+,D0
  720.         CMP.L    WindowPtr(A6),D0        ; was it in the front window?
  721.         BNE.S    @1                        ; no, then just select window
  722.         
  723.         MOVE.L    WindowPtr(A6),-(SP)        ; pass the window pointer
  724.         MOVE.L    EventPtr(A6),-(SP)        ; pass a pointer to the event
  725.         BSR        DoContentClick            ; do a click in content region
  726.         BRA.S    Exit
  727.         
  728. @1        MOVE.L    WindowPtr(A6),-(SP)        ; only select this window
  729.         _SelectWindow                    ; and take no further action
  730.         BRA.S    Exit
  731.  
  732. * ------------- THE DRAG A WINDOW EVENT -------------
  733. Drag        
  734.         MOVE.L    WindowPtr(A6),-(SP)        ; pass Window Pointer
  735.         MOVE.L    Mouse(A6),-(SP)            ; Mouse coordinates and boundary
  736.         PEA    QD.screenBits.bounds    
  737.         _DragWindow                        ; drag it the screen's boundary
  738.  
  739. Exit        
  740.         UNLK    A6                        ; destroy the link
  741.         MOVEA.L    (SP)+,A0                ; pull off the return address
  742.         ADDA.L    #ParamSize,SP            ; strip all of the caller's parameters
  743.         JMP    (A0)                        ; return to the caller
  744.  
  745.         DbgInfo    MouseDwn                ; this name will appear in the debugger
  746.         ENDP
  747.         
  748.         
  749. * ================================================
  750. * PROCEDURE DoEvent(event: EventRecord);
  751. * ================================================
  752. * Do the right thing for an event. Determine what kind of event it is,
  753. * and call the appropriate routines.
  754.  
  755.         SEG    'Main'                        ; case sensitive
  756. DoEvent        PROC
  757.  
  758. ModifyReg    EQU    D4                        ; we'll use this register locally
  759.  
  760. StackFrame    RECORD    {A6Link},DECR        ; build a stack frame record
  761. ParamBegin    EQU    *                        ; start listing parameters here
  762. EventPtr     DS.L    1                     ; pointer to current event
  763. ParamSize    EQU    ParamBegin-*            ; size of all the passed parameters
  764. RetAddr     DS.L    1                    ; place holder for return address
  765. A6Link        DS.L    1                    ; place holder for A6 link
  766. TheEvent     DS    EventRecord             ; local copy of the event record
  767. LocalSize    EQU     *                    ; size of all the local variables
  768.         ENDR
  769.  
  770.         IMPORT    DoMouseDown,DrawWindow,    \
  771.             AdjustMenus,IsAppWindow,\
  772.             DoUpdate,DoActivate
  773.         
  774.         WITH    StackFrame,TheEvent            ; cover our local stack frame
  775.         LINK    A6,#LocalSize                ; allocate our local stack frame
  776.         MOVEM.L    ModifyReg,-(SP)                ; save this register before using it
  777.     
  778.         MOVEA.L    EventPtr(A6),A0                ; pointer of event passed by caller
  779.         LEA    TheEvent(A6),A1                    ; pointer to local variable TheEvent
  780.         MOVE.L    #EventRecord.sizeof,D0        ; size of an event record
  781.         _BlockMove                            ; we now have a local copy of the event
  782.  
  783.         MOVE.W    modifiers(A6),ModifyReg        ; a nifty Pascal case-like macro
  784.         MOVE.W    What(A6),D0                    ; get the event number
  785.         Case#    (D0,Exit),    \                ; if not an event we support, then exit
  786.             ,        \                        ;  0 Null (not used)
  787.             MouseDownEvt,    \                ;  1 Mouse down
  788.             ,        \                        ;  2 Mouse up (not used)
  789.             KeyDownEvt,    \                    ;  3 Key down
  790.             ,        \                        ;  4 Key up (not used)
  791.             KeyDownEvt,    \                    ;  5 Auto key
  792.             Update,     \                    ;  6 Update
  793.             Disk,        \                    ;  7 Disk inserted
  794.             Activate,    \                    ;  8 Activate/Deactivate
  795.             ,        \                        ;  9 (not used)
  796.             ,        \                        ; 10 Network (not used)
  797.             ,        \                        ; 11 I/O Driver (not used)
  798.             ,        \                        ; 12 App1 (not used)
  799.             ,        \                        ; 13 App2 (not used)
  800.             ,        \                        ; 14 App3 (not used)
  801.             OSEvent,                        ; 15 OS Event or Suspend/Resume
  802.  
  803.  
  804. * ------------- THE MOUSEDOWN EVENT -------------
  805. MouseDownEvt    
  806.  
  807.         PEA    TheEvent(A6)                    ; pass Event pointer in case of SystemClick
  808.         BSR    DoMouseDown
  809.         BRA    Exit
  810.  
  811. * ------------- THE KEYDOWN EVENT -------------
  812. KeyDownEvt        
  813.         BTST    #CmdKey,ModifyReg            ; command key?
  814.         BEQ    Exit                            ; no, then we're done
  815.         BSR.W    AdjustMenus                    ; first, adjust the menus
  816.         CLR.L    -(SP)                        ; space for MenuKey
  817.         MOVE.W    2+Message(A6),-(SP)            ; get the character
  818.         _MenuKey                            ; is it a command?
  819.         BSR    DoMenuCommand                    ; handle the command and return
  820.         BRA.S    Exit
  821.  
  822. * ------------- THE UPDATE EVENT -------------
  823. Update    
  824.         MOVE.L    Message(A6),-(SP)            ; pass the window pointer
  825.         BSR    DoUpdate                        ; do the update
  826.         BRA.S    Exit
  827.  
  828. * ------------- THE DISK EVENT -------------
  829. Disk    
  830.         TST.W    Message(A6)                    ; check for error
  831.         BEQ.S    @1                            ; if none, skip
  832.         CLR.W    -(SP)
  833.         MOVE.L    #DITopLeft,-(SP)
  834.         MOVE.L    Message(A6),-(SP)
  835.         _DIBadMount
  836.         ADDQ    #2,SP                        ; throw away result
  837. @1        BRA.S    Exit
  838.  
  839. * ------------- THE ACTIVATE/DEACTIVATE EVENT -------------
  840. Activate    
  841.         BTST    #ActiveFlag,ModifyReg        ; was it an Activate?
  842.         BEQ.S    @1                            ; no, perform a Deactivate
  843.  
  844.         MOVE.L    Message(A6),-(SP)            ; pass the current window pointer
  845.         MOVE.W    #True100,-(SP)                ; set up for an Activate event
  846.         BSR    DoActivate                        ; do the activate routine
  847.         BRA.S    Exit                        ; we're done
  848.  
  849. @1        MOVE.L    Message(A6),-(SP)            ; pass current window pointer
  850.         MOVE.W    #False,-(SP)                ; set up for an Deactivate event
  851.         BSR    DoActivate                        ; go do the activate routine
  852.         BRA.S    Exit                        ; we're done
  853.  
  854. * ------------- THE SUSPEND/RESUME EVENT -------------
  855. * OSEvent is the event number of the suspend/resume and mouse-moved events sent
  856. * by MultiFinder. Once we determine that an event is an osEvent, we look at the
  857. * high byte of the message sent to determine which kind it is. To differentiate
  858. * suspend and resume events we check the resumeMask bit.
  859.  
  860. OSEvent        MOVE.B    Message(A6),D1            ; get high byte of Message in reg
  861.         CMPI.B    #SuspendResume,D1            ; test for message event type
  862.         BNE.S    Exit                        ; not a suspend/resume event
  863.     
  864.         BTST    #0,3+Message(A6)            ; test bit zero in low byte of Message
  865.         BNE.S    @1                            ; this is a resume event
  866.         
  867.         MOVE.W    #True100,G.InBackground        ; a suspend event
  868.         CLR.L    -(SP)                        ; bug fix, was passing Message to DoActivate -JDR 2/27/89 
  869.         _FrontWindow                        ; pass the front window to DoActivate -JDR 2/27/89
  870.         MOVE.W    #False,-(SP)                ; pass false to cause deactivate
  871.         BSR    DoActivate                        ; go do the activate routine
  872.         BRA.S    Exit
  873.  
  874. @1        MOVE.W    #False,G.InBackground        ; a resume event
  875.         CLR.L    -(SP)                        ; bug fix, was passing Message to DoActivate -JDR 2/27/89 
  876.         _FrontWindow                        ; pass the front window to DoActivate -JDR 2/27/89
  877.         MOVE.W    #True100,-(SP)                ; pass false to cause activate
  878.         BSR    DoActivate                        ; go do the activate routine
  879.         
  880. Exit        
  881.         MOVEM.L    (SP)+,ModifyReg                ; restore this register after use
  882.         UNLK    A6
  883.         MOVEA.L    (SP)+,A0                    ; save the caller's address
  884.         ADDA.L    #ParamSize,SP                ; strip the caller's parameters
  885.         JMP    (A0)
  886.  
  887.         DbgInfo    DoEvent                        ; this name will appear in the debugger
  888.         ENDP
  889.         
  890. * ================================================
  891. * PROCEDURE EventLoop;
  892. * ================================================
  893. * Get the events by calling WaitNextEvent, if it's available, otherwise
  894. * by calling GetNextEvent. Also call AdjustCursor before doing the event.
  895. * After returning from handling the event, we have to make sure the cursor
  896. * is still adjusted proper ONLY because this application can "sleep" forever.
  897.  
  898. * An event record is allocated on the stack.  A pointer to this event is
  899. * passed to "DoEvent".  We loop until the user has selects "Quit" in the
  900. * file menu.  This program will exit through the DoMenuCommand routine.
  901.  
  902. * 1.02 made adjustments to the event loop logic.  There was a bug in calling
  903. * AdjustCursor at the wrong time. (it crashed under _GetNextEvent too!)
  904.  
  905. * If you are using modeless dialogs that have editText items,
  906. * you will want to call IsDialogEvent to give the caret a chance
  907. * to blink, even if WNE/GNE returned FALSE. However, check FrontWindow
  908. * for a non-NIL value before calling IsDialogEvent.
  909.  
  910.         SEG    'Main'                        ; case sensitive
  911. EventLoop    PROC                        ; any source file can use this routine
  912.  
  913. StackFrame    RECORD    {A6Link},DECR        ; build a stack frame record
  914. ParamBegin    EQU    *                        ; start listing parameters here
  915. ParamSize    EQU    ParamBegin-*            ; size of all the passed parameters
  916. RetAddr     DS.L    1                    ; place holder for return address
  917. A6Link        DS.L    1                    ; place holder for A6 link
  918. TheEvent     DS    EventRecord             ; local copy of the event record
  919. MouseMvdRgn    DS.L    1                    ; local region for MouseMoved events
  920. MousePos    DS.L    1                    ; local point for mouse position
  921. LocalSize    EQU     *                    ; size of all the local variables
  922.         ENDR
  923.         
  924.         IMPORT    AdjustCursor,GetGlobalMouse
  925.  
  926.         WITH    StackFrame                ; cover our local stack frame
  927.         LINK    A6,#LocalSize            ; allocate our local stack frame
  928.         
  929.         CLR.L    -(SP)
  930.         _NewRgn                            ; create region for AdjustCursor
  931.         MOVE.L    (SP)+,MouseMvdRgn(A6)    ; save the handle to this region
  932.  
  933. * ------------- GET NEXT EVENT LOOP -------------
  934. NextEvent    
  935.         CMPI.W    #True100,G.HasWNEvent     ; see if we can call WaitNextEvent
  936.         BNE.S    @1                        ; nope, old time events
  937.         
  938.         PEA    MousePos(A6)                ; here's the mouse
  939.         BSR    GetGlobalMouse                ; get global coordinate
  940.         MOVE.L    MousePos(A6),-(SP)        ; here's the mouse
  941.         MOVE.L    MouseMvdRgn(A6),-(SP)    ; the region to change
  942.         BSR    AdjustCursor                ; adjust the cursor and region
  943.         CLR.W    -(SP)                    ; space for result
  944.         MOVE.W    #EveryEvent,-(SP)        ; the events we want
  945.         PEA    TheEvent(A6)                ; pointer to the event record
  946.         MOVE.L    #SleepValue,-(SP)        ; the sleeping time value
  947.         MOVE.L    MouseMvdRgn(A6),-(SP)    ; the current MouseRgn
  948.         _WaitNextEvent
  949.         BRA.S    @2                        ; got an event to handle?
  950.     
  951.                                         ; no WaitNextEvent trap available
  952. @1        _SystemTask                        ; call SystemTask for drivers and DAs
  953.         CLR.W    -(SP)                    ; space for result
  954.         MOVE.W    #EveryEvent,-(SP)        ; the events we want
  955.         PEA    TheEvent(A6)                ; pass a pointer to our event
  956.         _GetNextEvent
  957. @2        MOVE.W    (SP)+,D0                ; result code
  958.         BEQ.S    NextEvent                ; no event, get another one
  959.         
  960. GotEvent    MOVE.L    TheEvent.where(A6),-(SP)    ; the mouse location
  961.         MOVE.L    MouseMvdRgn(A6),-(SP)            ; the region to change
  962.         BSR    AdjustCursor                        ; adjust cursor BEFORE doing event
  963.         PEA    TheEvent(A6)                        ; pass the pointer to our event
  964.         BSR    DoEvent                                ; do the event and return
  965.  
  966.         BRA.S    NextEvent                ; done with that event, get the next
  967.  
  968. Exit        UNLK    A6                    ; destroy the link
  969.         MOVEA.L    (SP)+,A0                ; pull off the return address
  970.         ADDA.L    #ParamSize,SP            ; strip all of the caller's parameters
  971.         JMP    (A0)                        ; return to the caller
  972.  
  973.         DbgInfo    EvntLoop                ; this name will appear in the debugger
  974.         ENDP
  975.  
  976. * ================================================
  977. * --------------- MAIN ENTRY POINT ---------------
  978. * ================================================
  979. * This is the entry point of the program.  We start with data initializing
  980. * and then to get the System environment (SysEnvirons).  We unload the
  981. * initialization code segment and finally get started with the EventLoop.
  982.  
  983.         SEG    'Main'                        ; case sensitive
  984. StartUp            MAIN                    ; entry point of the program
  985.         
  986.         IMPORT    _DataInit,Initialize,    \
  987.             ForceEnvirons,EventLoop
  988.  
  989.         JSR    _DataInit                    ; initialize those constants    
  990.         PEA    _DataInit                    ; get rid of that segment
  991.         _UnloadSeg
  992.  
  993. * If you have stack requirements that differ from the default, then you could
  994. * use SetApplLimit to increase StackSpace at this point, before calling MaxApplZone.
  995.  
  996.         _MaxApplZone                    ; result in D0
  997.         JSR    Initialize                    ; get things the program set up
  998.         PEA    Initialize
  999.         _UnloadSeg                        ; we're done this that segment too
  1000.         LEA    EventLoop,A0                ; on your mark, get set,...
  1001.         JMP    (A0)                        ; go into the event loop
  1002.         ENDP
  1003.  
  1004.         END                                ; end of this source file
  1005.  
  1006.